#include <iostream>
#include <fstream>
#include <string>
#include <unordered_map>
#include <vector>
#include <thread>
#include <chrono>
#include "json.hpp"
#include "tinyformat/tinyformat.h"
#include "termcolor/termcolor.hpp"

using namespace std;
using json = nlohmann::json;

struct GameState {
    string currentNode = "intro";
    string playerName;
    json data;
    
    unordered_map<string, int> attributes;
    unordered_map<string, bool> inventory;
    vector<string> history;
    unordered_map<string, string> characters;
};

void clearScreen();
void typewriter(const string& text, int delay = 30);
bool checkCondition(const GameState& state, const json& condition);
void processEffects(GameState& state, const json& node);
void displayUI(GameState& state);
void handleInput(GameState& state);
void loadGame(GameState& state);
bool loadSave(GameState& state);
void saveGame(const GameState& state);

void clearScreen() {
#ifdef _WIN32
    system("cls");
#else
    system("clear");
#endif
}

void typewriter(const string& text, int delay) {
    string processed = text;
    size_t pos = 0;
    while ((pos = processed.find("#%#", pos)) != string::npos) {
        processed.replace(pos, 3, "\n");
        pos += 1;
    }

    for (char c : processed) {
        cout << c << flush;
        this_thread::sleep_for(chrono::milliseconds(delay));
    }
    cout << endl;
    cout << termcolor::magenta << "\n=== 按Enter继续 ===\n" << termcolor::reset;
    cin.ignore(numeric_limits<streamsize>::max(), '\n');
}

bool checkCondition(const GameState& state, const json& condition) {
    if (condition.contains("attribute")) {
        string attr = condition["attribute"];
        int value = state.attributes.at(attr);
        return value >= condition["min"];
    }
    if (condition.contains("item")) {
        return state.inventory.count(condition["item"]);
    }
    if (condition.contains("gold")) {
        return state.attributes.at("gold") >= condition["gold"];
    }
    return true;
}

void processEffects(GameState& state, const json& node) {
    if (node.contains("effects")) {
        for (auto& effect : node["effects"]) {
            if (effect.contains("attribute")) {
                string attr = effect["attribute"];
                int value = effect["value"];
                state.attributes[attr] += value;
            }
            if (effect.contains("item")) {
                string item = effect["item"];
                state.inventory[item] = true;
            }
        }
    }
}

void displayUI(GameState& state) {
    cout << termcolor::cyan << "\n[";
    for (auto& [key, val] : state.attributes) {
        cout << " " << key << ": " << val;
    }
    cout << " ]\n" << termcolor::reset;

    const json& current = state.data["nodes"][state.currentNode];
    string speaker = current.value("speaker", "旁白");
    speaker = (speaker == "player") ? state.playerName : speaker;

    state.history.push_back(speaker + ": " + current["text"].get<string>());

    cout << termcolor::yellow << "\n======== 剧情进展 ========\n" << termcolor::reset;
    cout << termcolor::cyan << speaker << ": " << termcolor::reset;
    typewriter(current["text"].get<string>());

    if (!current["choices"].empty()) {
        cout << termcolor::green << "\n可选操作:\n";
        int index = 1;
        for (auto& [text, choice] : current["choices"].items()) {
            cout << "  [" << index++ << "] " << text << "\n";
        }
        cout << termcolor::reset;
    }
}

void handleInput(GameState& state) {
    const json& current = state.data["nodes"][state.currentNode];
    
    while (true) {
        cout << termcolor::bright_blue << "\n输入选项编号"
             << " (i=物品 h=历史 q=退出): " << termcolor::reset;
        string input;
        cin >> input;

        if (input == "q") {
            cout << termcolor::red << "游戏已退出\n";
            exit(0);
        }
        if (input == "i") {
            cout << termcolor::yellow << "\n=== 背包物品 ===\n";
            for (auto& [item, _] : state.inventory) 
                cout << " - " << item << "\n";
            continue;
        }
        if (input == "h") {
            cout << termcolor::yellow << "\n=== 对话历史 ===\n";
            for (auto& entry : state.history) 
                cout << " > " << entry << "\n";
            continue;
        }

        try {
            int choice = stoi(input);
            if (choice < 1 || choice > current["choices"].size()) {
                throw out_of_range("无效选项");
            }

            auto it = current["choices"].begin();
            advance(it, choice-1);
            json choiceData = it.value();

            if (choiceData.contains("requires") && 
               !checkCondition(state, choiceData["requires"])) {
                cout << termcolor::red << "条件不满足！需要：";
                if (choiceData["requires"].contains("attribute")) {
                    cout << choiceData["requires"]["attribute"] 
                         << " ≥ " << choiceData["requires"]["min"];
                }
                if (choiceData["requires"].contains("item")) {
                    cout << "需要物品: " << choiceData["requires"]["item"];
                }
                cout << "\n" << termcolor::reset;
                continue;
            }

            if (choiceData.contains("effects")) {
                processEffects(state, choiceData);
            }

            state.currentNode = choiceData["next"].get<string>();
            return;

        } catch (...) {
            cout << termcolor::red << "无效输入，请重试\n" << termcolor::reset;
            cin.clear();
            cin.ignore();
        }
    }
}

void loadGame(GameState& state) {
    ifstream file("data.json");
    if (!file) {
        cerr << termcolor::red << "无法加载数据文件！" << termcolor::reset;
        exit(1);
    }
    file >> state.data;

    state.playerName = state.data["player"]["name"];
    for (auto& [attr, val] : state.data["player"]["attributes"].items()) {
        state.attributes[attr] = val;
    }

    for (auto& [name, desc] : state.data["characters"].items()) {
        state.characters[name] = desc;
    }
}

bool loadSave(GameState& state) {
    ifstream file("save.json");
    if (!file) return false;

    json progress;
    file >> progress;
    
    state.currentNode = progress["current"];
    for (auto& [attr, val] : progress["attributes"].items()) {
        state.attributes[attr] = val;
    }
    for (auto& item : progress["inventory"]) {
        state.inventory[item] = true;
    }
    return true;
}

void saveGame(const GameState& state) {
    json progress;
    progress["current"] = state.currentNode;
    progress["attributes"] = state.attributes;
    progress["inventory"] = json::array();
    for (auto& item : state.inventory) progress["inventory"].push_back(item.first);

    ofstream("save.json") << progress.dump(4);
}

int main() {
    GameState state;
    loadGame(state);
    clearScreen();

    bool hasSave = loadSave(state);
    if (hasSave) {
        cout << termcolor::yellow << "检测到存档，是否加载？(y/n): ";
        char choice;
        cin >> choice;
        if (tolower(choice) != 'y') {
            state.currentNode = "intro";
            state.inventory.clear();
        }
    }

    while (true) {
        clearScreen();
        
        if (state.data["endings"].contains(state.currentNode)) {
            cout << termcolor::blink << termcolor::green 
                 << "\n=== 结局 ===\n"
                 << state.data["endings"][state.currentNode] 
                 << termcolor::reset << "\n\n";
            break;
        }

        displayUI(state);
        handleInput(state);
        saveGame(state);
    }

    return 0;
}